package com.eva.admin.biz.cms.category;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.eva.admin.biz.cms.category.dto.QueryCmsCategoryDTO;
import com.eva.admin.biz.cms.category.dto.UpdateCmsCategoryDTO;
import com.eva.admin.biz.cms.category.dto.UpdateCmsCategoryStatusDTO;
import com.eva.admin.biz.cms.category.vo.CmsCategoryNodeVO;
import com.eva.admin.dao.cms.CmsCategoryMapper;
import com.eva.admin.biz.cms.category.dto.CreateCmsCategoryDTO;
import com.eva.admin.biz.cms.category.vo.CmsCategoryVO;
import com.eva.dao.cms.model.CmsArticle;
import com.eva.framework.common.constants.ResponseStatus;
import com.eva.framework.common.exception.BusinessException;
import com.eva.framework.common.utils.AssertUtil;
import com.eva.dao.cms.model.CmsCategory;
import com.eva.framework.rbac.model.RbacUserInfo;
import com.eva.framework.rbac.session.SessionUtil;
import com.eva.service.cms.CmsArticleService;
import com.eva.service.cms.CmsCategoryService;
import com.eva.service.system.SystemPermissionService;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;

@Service
public class CmsCategoryBiz {

    @Resource
    private CmsCategoryMapper cmsCategoryMapper;

    @Resource
    private CmsCategoryService cmsCategoryService;

    @Resource
    private CmsArticleService cmsArticleService;

    @Resource
    private SystemPermissionService systemPermissionService;

    /**
     * 创建
     *
     * @param dto 创建参数
     */
    @Transactional
    public void create(CreateCmsCategoryDTO dto) {
        // 验证
        AssertUtil.notEmpty(dto.getTitle(), "栏目标题不能为空");
        AssertUtil.notEmpty(dto.getType(), "栏目类型不能为空");
        AssertUtil.notEmpty(dto.getSort(), "排序不能为空");
        // 验证父栏目
        if (dto.getParentId() != null) {
            this.checkParent(dto.getParentId(), null);
        }
        // 验证唯一标识
        if (cmsCategoryService.exists(CmsCategory.builder().uid(dto.getUid()).build())) {
            throw new BusinessException(ResponseStatus.DATA_EXISTS, "唯一标识已存在");
        }
        // 构建对象
        CmsCategory newRecord = new CmsCategory();
        BeanUtils.copyProperties(dto, newRecord);
        // - 权限处理
        newRecord.setPermissionId(systemPermissionService.create(dto.getPermission(), "栏目/" + dto.getTitle()));
        // 执行创建
        cmsCategoryService.create(newRecord);
    }

    /**
     * 根据主键删除
     *
     * @param id 主键
     */
    @Transactional
    public void deleteById(Integer id) {
        AssertUtil.notEmpty(id, "主键不能为空");
        CmsCategory category = cmsCategoryService.findById(id);
        if (category == null) {
            return;
        }
        // 越权验证
        this.checkPrivilege(category);
        // 查询子栏目主键集合
        Set<Integer> ids = this.findChildIdsWithPermission(id);
        ids.add(id);
        // 查询出所有待删除的栏目
        List<CmsCategory> categories = cmsCategoryService.findByIds(ids);
        List<CmsCategory> deleteList = new ArrayList<>();
        // 循环删除栏目
        for (CmsCategory m : categories) {
            // 删除权限
            systemPermissionService.deleteByIdAllowNull(m.getPermissionId());
            // 添加到待删除列表
            CmsCategory newCategory = new CmsCategory();
            newCategory.setId(m.getId());
            // - 保留父栏目ID
            newCategory.setParentId(m.getParentId());
            newCategory.setDeleted(Boolean.TRUE);
            deleteList.add(newCategory);
        }
        // 批量删除栏目
        cmsCategoryService.updateByIdInBatch(deleteList);
        // 删除栏目下的文章
        for (Integer categoryId : ids) {
            UpdateWrapper<CmsArticle> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda()
                    .set(CmsArticle::getDeleted, Boolean.TRUE)
                    .like(CmsArticle::getCategoryIds, StringUtils.join(",",categoryId,","))
                    .eq(CmsArticle::getDeleted, Boolean.FALSE)
            ;
            cmsArticleService.update(updateWrapper);
        }

    }

    /**
     * 根据主键批量删除
     *
     * @param ids 主键集合
     */
    @Transactional
    public void deleteByIdInBatch(List<Integer> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return;
        }
        for (Integer id : ids) {
            this.deleteById(id);
        }
    }

    /**
     * 修改
     *
     * @param dto 修改参数
     */
    @Transactional
    public void updateById(UpdateCmsCategoryDTO dto) {
        // 基础验证
        AssertUtil.notEmpty(dto.getTitle(), "栏目标题不能为空");
        AssertUtil.notEmpty(dto.getType(), "栏目类型不能为空");
        AssertUtil.notEmpty(dto.getSort(), "排序不能为空");
        AssertUtil.notEmpty(dto.getUid(), "唯一标识不能为空");
        CmsCategory category = cmsCategoryService.findById(dto.getId());
        AssertUtil.notEmpty(category, "栏目不存在");
        // 越权验证
        this.checkPrivilege(category);
        // 验证上级菜单
        if (dto.getParentId() != null) {
            this.checkParent(dto.getParentId(), dto.getId());
        }
        // 验证唯一标识
        if (cmsCategoryService.exists(CmsCategory.builder().id(dto.getId()).uid(dto.getUid()).build())) {
            throw new BusinessException(ResponseStatus.DATA_EXISTS, "唯一标识已存在");
        }
        // 执行修改
        CmsCategory newRecord = CmsCategory.builder().build();
        BeanUtils.copyProperties(dto, newRecord);
        // - 绑定权限ID，sync方法会自动根据参数处理权限，返回null或实际权限ID
        newRecord.setPermissionId(systemPermissionService.sync(
                category.getPermissionId(),
                dto.getPermission(),
                "栏目/" + dto.getTitle())
        );
        cmsCategoryService.updateById(newRecord);
        // - 模板ID处理（如果模板ID为null，则改为null）
        if (dto.getTemplateId() == null) {
            UpdateWrapper<CmsCategory> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda()
                    .set(CmsCategory::getTemplateId, null)
                    .set(CmsCategory::getTemplateParameters, null)
                    .eq(CmsCategory::getId, newRecord.getId());
            cmsCategoryService.update(updateWrapper);
        }
    }

    /**
     * 修改栏目状态
     *
     * @param dto 修改参数
     */
    public void updateStatus (UpdateCmsCategoryStatusDTO dto) {
        // 基础验证
        AssertUtil.notNull(dto.getId(), "栏目ID不能为空");
        AssertUtil.notNull(dto.getHidden(), "隐藏状态不能为空");
        // 查询栏目
        CmsCategory category = cmsCategoryService.findById(dto.getId());
        AssertUtil.notEmpty(category, "栏目不存在");
        // 修改状态，采用UpdateWrapper实现，避免影响父栏目和权限ID
        UpdateWrapper<CmsCategory> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda()
                .set(CmsCategory::getHidden, dto.getHidden())
                .eq(CmsCategory::getId, dto.getId());
        cmsCategoryService.update(updateWrapper);
    }

    /**
     * 查询栏目树
     * - 仅查询拥有权限的栏目并将其组装为树
     *
     * @return List<CategoryNodeVO>
     */
    public List<CmsCategoryNodeVO> findTree () {
        // 查询用户拥有的栏目
        RbacUserInfo loginUserInfo = SessionUtil.getLoginUser();
        QueryCmsCategoryDTO dto = new QueryCmsCategoryDTO();
        dto.setIsSuperAdmin(loginUserInfo.getIsSuperAdmin());
        // - 非超级管理员，补充权限ID集
        if (!loginUserInfo.getIsSuperAdmin()) {
            dto.setPermissionIds(loginUserInfo.getCategoryPermissionIds());
        }
        List<CmsCategoryVO> categories = cmsCategoryMapper.search(dto);
        // 转为树
        return cmsCategoryService.transferToTree(categories, CmsCategoryNodeVO.class);
    }

    /**
     * 验证上级栏目
     *
     * @param parentId 上级栏目主键
     * @param currentCategoryId 当前栏目主键
     */
    private void checkParent (Integer parentId, Integer currentCategoryId) {
        CmsCategory parent = cmsCategoryService.findById(parentId);
        // 验证上级栏目是否存在
        AssertUtil.notNull(parent, "上级栏目不存在");
        // 验证上级栏目是否合理
        if (currentCategoryId != null && currentCategoryId.equals(parentId)) {
            throw new BusinessException(ResponseStatus.NOT_ALLOWED, "上级栏目不能为当前栏目");
        }
        if (!StringUtils.isBlank(parent.getUri())) {
            throw new BusinessException(ResponseStatus.NOT_ALLOWED, "上级栏目必须为一个常规栏目");
        }
        // 验证上级栏目是否越权
        this.checkPrivilege(parent);
    }

    /**
     * 越权验证
     *
     * @param currentCategory 当前栏目
     */
    private void checkPrivilege (CmsCategory currentCategory) {
        RbacUserInfo userInfo = SessionUtil.getLoginUser();
        // 超级管理员
        if (userInfo.getIsSuperAdmin()) {
            return;
        }
        // 非超级管理员
        if (currentCategory.getPermissionId() != null) {
            // 如果是自己创建的栏目，即使没有权限也可操作
            if (currentCategory.getCreatedBy().equals(userInfo.getId())) {
                return;
            }
            // 如果不存在该栏目权限，视为越权
            if (!SessionUtil.getLoginUser()
                    .getMenuPermissionIds()
                    .contains(currentCategory.getPermissionId())
            ) {
                throw new BusinessException(ResponseStatus.PRIVILEGE_ERROR);
            }
        }
    }

    /**
     * 结合用户菜单权限查询子孙菜单ID
     *
     * @param menuId 菜单ID
     * @return 子孙菜单ID集
     */
    private Set<Integer> findChildIdsWithPermission(Integer menuId) {
        RbacUserInfo loginUser = SessionUtil.getLoginUser();
        Set<Integer> pool = new LinkedHashSet<>();
        this.fillChildren(pool, Collections.singleton(menuId), loginUser);
        return pool;
    }

    /**
     * 填充子栏目ID
     *
     * @param pool 子栏目集合，用于记录子栏目ID
     * @param parentIds 父栏目ID
     */
    public void fillChildren(Set<Integer> pool, Set<Integer> parentIds, RbacUserInfo loginUserInfo) {
        if (loginUserInfo.getIsSuperAdmin() && loginUserInfo.getCategoryPermissionIds().isEmpty()) {
            QueryWrapper<CmsCategory> wrapper = new QueryWrapper<>();
            wrapper.lambda()
                    .in(CmsCategory::getParentId, parentIds)
                    .eq(CmsCategory::getDeleted, Boolean.FALSE)
            ;
            Set<Integer> ids = cmsCategoryService.findIds(wrapper);
            if (ObjectUtils.isNotEmpty(ids)) {
                pool.addAll(ids);
                this.fillChildren(pool, ids, loginUserInfo);
            }
            return;
        }
        QueryWrapper<CmsCategory> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .in(CmsCategory::getParentId, parentIds)
                // 拥有权限的栏目 和 不需要权限的栏目
                .and(qw -> qw
                        .in(CmsCategory::getPermissionId, loginUserInfo.getCategoryPermissionIds())
                        .or()
                        .isNull(CmsCategory::getPermissionId)
                )
                .eq(CmsCategory::getDeleted, Boolean.FALSE)
        ;
        Set<Integer> ids = cmsCategoryService.findIds(queryWrapper);
        if (ids.size() > 0) {
            pool.addAll(ids);
            this.fillChildren(pool, ids, loginUserInfo);
        }
    }
}
